﻿Imports System
Imports System.Management
Imports System.Reflection
Imports System.IO
Imports Microsoft.Win32
Imports System.Security.Permissions
Imports System.Environment
Imports System.Xml
Imports System.Xml.XPath
Imports System.Xml.Xsl

Module Module1
    Private Const REGPATH As String = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\FIMSynchronizationService\Parameters"
    Private Const WMINAMESPACE As String = "root\MicrosoftIdentityIntegrationServer"

    Sub GetExportFlows(xmlDoc As XmlDocument)
        Try
            Dim di As New IO.DirectoryInfo(GetDataFolder)
            For Each fi As FileInfo In di.GetFiles("MA-*.xml")
                Dim maDoc As New XmlDocument
                maDoc.Load(fi.FullName)
                For Each curNode As XmlElement In maDoc.SelectNodes("//export-flow-set")
                    Dim flowsetNode As XmlElement
                    If (xmlDoc.SelectNodes("//flow-set[@mv-object-type='" + curNode.GetAttribute("mv-object-type").ToString + "']").Count = 0) Then
                        flowsetNode = xmlDoc.CreateElement("flow-set")
                        flowsetNode.SetAttribute("mv-object-type", curNode.GetAttribute("mv-object-type").ToString)
                        xmlDoc.SelectSingleNode("//mv-object-types").AppendChild(flowsetNode)
                    Else
                        flowsetNode = xmlDoc.SelectSingleNode("//flow-set[@mv-object-type='" + curNode.GetAttribute("mv-object-type").ToString + "']")
                    End If

                    For Each curnode2 As XmlElement In curNode.SelectNodes(".//src-attribute")
                        Dim flowsNode As XmlElement
                        If (flowsetNode.SelectNodes("flows[@mv-attribute='" + curnode2.InnerText + "']").Count = 0) Then
                            flowsNode = xmlDoc.CreateElement("flows")
                            flowsNode.SetAttribute("mv-attribute", curnode2.InnerText)
                        Else
                            flowsNode = flowsetNode.SelectSingleNode("flows[@mv-attribute='" + curnode2.InnerText + "']")
                        End If

                        Dim expNode As XmlElement = xmlDoc.ImportNode(curnode2.ParentNode.ParentNode, True)
                        expNode.SetAttribute("src-ma", fi.Name.Substring(fi.Name.IndexOf("{"), fi.Name.IndexOf("}") - 2))
                        expNode.SetAttribute("cd-object-type", curnode2.ParentNode.ParentNode.ParentNode.Attributes("cd-object-type").ToString)
                        expNode.SetAttribute("mv-object-type", curnode2.ParentNode.ParentNode.ParentNode.Attributes("mv-object-type").ToString)
                        flowsNode.AppendChild(expNode)
                    Next
                Next
            Next
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Sub GetImportFlows(xmlDoc As XmlDocument)
        Try
            Dim mvDoc As New XmlDocument
            mvDoc.Load(GetMVFilePath)
            For Each curNode As XmlElement In mvDoc.SelectNodes("//import-flow-set")
                Dim flowsetNode As XmlElement = xmlDoc.CreateElement("flow-set")
                flowsetNode.SetAttribute("mv-object-type", curNode.GetAttribute("mv-object-type"))
                xmlDoc.SelectSingleNode("//mv-object-types").AppendChild(flowsetNode)
                For Each flowsNode As XmlElement In curNode.ChildNodes()
                    Dim flowNode As XmlElement = xmlDoc.CreateElement("flows")
                    flowNode.SetAttribute("mv-attribute", flowsNode.GetAttribute("mv-attribute"))
                    flowNode.SetAttribute("type", flowsNode.GetAttribute("type"))
                    flowsetNode.AppendChild(flowNode)
                    For Each iFlowNode As XmlElement In flowsNode.ChildNodes
                        Dim importNode As XmlElement = xmlDoc.ImportNode(iFlowNode, True)
                        flowNode.AppendChild(importNode)
                    Next
                Next
            Next
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Sub GetMaConfig(xmlDoc As XmlDocument, curNode As XmlElement)
        Dim sQuery As String = "SELECT * FROM MIIS_ManagementAgent"
        Dim wmiSearcher As New ManagementObjectSearcher(WMINAMESPACE, sQuery)
        Dim obCollection As ManagementObjectCollection = wmiSearcher.Get()
        Dim curObject As ManagementObject

        Try
            For Each curObject In obCollection
                Dim maNode As XmlElement = xmlDoc.CreateElement("ma")
                curNode.AppendChild(maNode)
                maNode.SetAttribute("name", curObject.Properties("Name").Value)
                maNode.SetAttribute("guid", curObject.Properties("Guid").Value)
            Next
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

    Function GetMaStats(sManagementAgent As String) As String
        GetMaStats = ""
        Dim sStats As String = ""
        Try
            Dim sQuery As String = "SELECT * FROM MIIS_ManagementAgent WHERE Name = '" + sManagementAgent + "'"
            Dim wmiSearcher As New ManagementObjectSearcher(WMINAMESPACE, sQuery)
            Dim obCollection As ManagementObjectCollection = wmiSearcher.Get()
            Dim curObject As ManagementObject

            For Each curObject In obCollection
                sStats += "<table style=""font-family:Tahoma;font-size:11px; border: 1px RGB(212,208,200) solid;"">"
                sStats += "<tr><td colspan = ""2"" style=""padding-top: 10px;padding-bottom: 10px;padding-left: 10px;"
                sStats += "padding-right: 10px;font-weight: bold;background: rgb(234,242,255);border-bottom: 1px solid rgb(120,172,255);"
                sStats += """>" + sManagementAgent + "</td></tr>"


                sStats += "<tr><td colspan = ""2"""
                sStats += " style=""text-align:left;border-bottom: green 1px solid;padding-bottom: 5px;padding-left: 10px;"
                sStats += "padding-right: 10px;background: #e9ffcb;font-weight: bold;padding-top: 5px"">"
                sStats += "General</td></tr>"

                sStats += "<tr><td style=""padding-left:5px;"">Count</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumCSObjects", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Placeholders</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumPlaceholders", Nothing) + "</td></tr>"

                sStats += "<tr><td colspan = ""2"""
                sStats += " style=""text-align:left;border-bottom: green 1px solid;padding-bottom: 5px;padding-left: 10px;"
                sStats += "padding-right: 10px;background: #e9ffcb;font-weight: bold;padding-top: 5px"">"
                sStats += "Connectors</td></tr>"

                sStats += "<tr><td style=""padding-left:5px;"">Total</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumTotalConnectors", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Count</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumConnectors", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Explicit</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumExplicitConnectors", Nothing) + "</td></tr>"


                sStats += "<tr><td colspan = ""2"""
                sStats += " style=""text-align:left;border-bottom: green 1px solid;padding-bottom: 5px;padding-left: 10px;"
                sStats += "padding-right: 10px;background: #e9ffcb;font-weight: bold;padding-top: 5px"">"
                sStats += "Disconnectors</td></tr>"

                sStats += "<tr><td style=""padding-left:5px;"">Total</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumTotalDisconnectors", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Count</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumDisconnectors", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Explicit</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumExplicitDisconnectors", Nothing) + "</td></tr>"

                sStats += "<tr><td colspan = ""2"""
                sStats += " style=""text-align:left;border-bottom: green 1px solid;padding-bottom: 5px;padding-left: 10px;"
                sStats += "padding-right: 10px;background: #e9ffcb;font-weight: bold;padding-top: 5px"">"
                sStats += "Import</td></tr>"

                sStats += "<tr><td style=""padding-left:5px;"">Unchanged</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumImportNoChange", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Add</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumImportAdd", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Update</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumImportUpdate", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Delete</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumImportDelete", Nothing) + "</td></tr>"

                sStats += "<tr><td colspan = ""2"""
                sStats += " style=""text-align:left;border-bottom: green 1px solid;padding-bottom: 5px;padding-left: 10px;"
                sStats += "padding-right: 10px;background: #e9ffcb;font-weight: bold;padding-top: 5px"">"
                sStats += "Export</td></tr>"

                sStats += "<tr><td style=""padding-left:5px;"">Add</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumExportAdd", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Update</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumExportUpdate", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Delete</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("NumExportDelete", Nothing) + "</td></tr>"

                sStats += "<tr><td colspan = ""2"""
                sStats += " style=""text-align:left;border-bottom: green 1px solid;padding-bottom: 5px;padding-left: 10px;"
                sStats += "padding-right: 10px;background: #e9ffcb;font-weight: bold;padding-top: 5px"">"
                sStats += "Run Profile</td></tr>"

                sStats += "<tr><td style=""padding-left:5px;"">Name</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("RunProfile", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Time</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("RunStartTime", Nothing) + "</td></tr>"
                sStats += "<tr><td style=""padding-left:5px;"">Status</td><td style=""padding-left:5px;"">" + curObject.InvokeMethod("RunStatus", Nothing) + "</td></tr>"

                sStats += "</table>"

                Return sStats
            Next
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Function GetDataFolder() As String
        Dim sAppDataFolder As String = GetFolderPath(SpecialFolder.CommonApplicationData)
        Return sAppDataFolder + "\" + My.Application.Info.AssemblyName
    End Function

    Function GetMVFilePath() As String
        Try
            Dim sName As String = My.Application.Info.AssemblyName
            Dim sAppDataFolder As String = GetFolderPath(SpecialFolder.CommonApplicationData)
            Dim sDataFolder As String = sAppDataFolder + "\" + sName

            Return sDataFolder + "\MV.XML"
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Function Transform(ByVal xslFile As String, ByVal xmlDoc As XmlDocument, ByVal xslArg As String) As String
        Try
            Dim XslFilePath As String = My.Application.Info.DirectoryPath & "\Res\" & xslFile
            If Not File.Exists(XslFilePath) Then
                Throw New Exception("XSLT file not found: " & xslFile)
            End If

            Dim xmlTextReader As New XmlTextReader(XslFilePath)
            Dim memStream As MemoryStream = New MemoryStream
            Dim xsltArgs As XsltArgumentList = New XsltArgumentList

            If (xslArg.Length > 0) Then
                xsltArgs.AddParam("filter", "", xslArg)
            End If

            Dim xslSettings As New XsltSettings
            xslSettings.EnableScript = True

            Dim xslTrans As New XslCompiledTransform
            xslTrans.Load(xmlTextReader, xslSettings, New XmlUrlResolver)
            xslTrans.Transform(xmlDoc.CreateNavigator, xsltArgs, memStream)

            Dim stmReader As StreamReader = New StreamReader(memStream)
            memStream.Position = 0

            Dim sRetVal As String = stmReader.ReadToEnd
            stmReader.Close()
            Return sRetVal
        Catch ex As Exception
            Throw ex
        End Try
    End Function

    Sub ExportData()
        Try
            Dim myAssembly As Assembly = Assembly.GetExecutingAssembly
            myAssembly.GetManifestResourceNames()

            Dim sName As String = My.Application.Info.AssemblyName
            Dim sAppDataFolder As String = GetFolderPath(SpecialFolder.CommonApplicationData)
            Dim sDataFolder As String = sAppDataFolder + "\" + sName

            If Directory.Exists(sDataFolder) Then
                Dim di As New DirectoryInfo(sDataFolder)
                Dim fi As FileInfo
                For Each fi In di.GetFiles()
                    fi.Attributes = FileAttributes.Normal
                Next
                Directory.Delete(sDataFolder, True)
            End If

            Directory.CreateDirectory(sDataFolder)

            Dim sAppPath As String = My.Computer.Registry.GetValue(REGPATH, "Path", "")
            If sAppPath.Length < 2 Then
                Throw New Exception("Failed to read path value from registry")
            End If

            Dim sAppName As String = sAppPath + "Bin\svrexport.exe"
            Dim myProcess As New Process

            myProcess.StartInfo.UseShellExecute = False
            myProcess.StartInfo.RedirectStandardError = True
            myProcess.StartInfo.RedirectStandardOutput = True
            myProcess.StartInfo.FileName = sAppName
            myProcess.StartInfo.Arguments = """" + sDataFolder + """"
            myProcess.StartInfo.CreateNoWindow = True
            myProcess.Start()
            Dim sError As String = myProcess.StandardError.ReadToEnd()
            Dim sOutput As String = myProcess.StandardOutput.ReadToEnd()
            myProcess.WaitForExit()

            If Not sOutput.Contains("Successfully") Then
                Throw New Exception(sOutput)
            End If

        Catch ex As Exception
            Throw ex
        End Try
    End Sub
End Module
